home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
14642
/
14642.xpi
/
chrome
/
modules
/
storage.js
< prev
next >
Wrap
Text File
|
2009-10-14
|
43KB
|
1,252 lines
/* Copyright 2008, Boomtango.com. All Rights Reserved. */
/* storage.js
* Responsible for data storage
*/
var EXPORTED_SYMBOLS = ["boomtangoStorage"];
var boomtangoStorage = {
DBVERSION: 1,
/*
Returns a SQL conditional fragment based on starttime, endtime, types. Output is expected to be
sanitized. Assumes 'types' is trusted and ensures starttime/endtime is an integer.
*/
_buildWhereClause: function(starttime, endtime, types, skipTimes, dedupe){
var r = [];
var start = parseInt(starttime);
var end = parseInt(endtime);
if(!skipTimes){
r.push( "(starttime>= ", start, " AND starttime<= ", end, ")");
}
if(types){
r.push(r.length ? " AND (" : " (");
var len = types.length;
for(var x = 0; x < len; ){
r.push("type = '", types[x], "'");
x++;
if(x < len){
r.push(" OR ");
}
}
r.push(")");
}
if(dedupe){
var where;
r.push(r.length ? " AND (" : " (");
r.push("ftsrowid not in (SELECT ftsrowid FROM tracker WHERE ");
where = this._buildWhereClause(start, end, null, skipTimes, false);
if (where) {
r.push(where + " AND ");
}
r.push("type != 'web')");
r.push(")");
}
return r.join("");
},
deleteAllThumb: function() {
this.app.log("storage::deleteAllThumb: ");
var sql = "DELETE FROM thumb;VACUUM;";
this.conn.executeSimpleSQL(sql);
},
updateThumb: function(id, data){
var now = Date.now();
var sql = ["UPDATE thumb SET data = ",
"'", data, "' , createtime = ", now, " WHERE ",
"id = ",id,
].join("");
this.conn.executeSimpleSQL(sql);
},
getThumbID: function(url){
var res = -1;
var sql = ["SELECT ",
"id,",
" createtime",
" FROM thumb WHERE url = ?1"
].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, url);
if (statement.executeStep()) {
res = {
id: statement.getInt64(0),
createtime: statement.getInt64(1)
};
}
if(res.id === undefined){
res = { id: -1 };
}
statement.reset();
return res;
},
getBlacklist: function(allrecs){
this.app.log("storage::getBlacklist");
var sql = ["SELECT ",
"data",
" FROM blacklist",
(allrecs ? "" : " WHERE internalOnly = 0")
].join("");
var statement = this.conn.createStatement(sql);
var res = [];
while (statement.executeStep()) {
res.push(statement.getString(0));
}
this.app.debug("Num Results: " + res.length);
statement.reset();
return res;
},
addBlacklistData: function(data, internalOnly){
this.app.log("storage::addBlacklistData (" + data + ")");
var sql = ["INSERT INTO blacklist (",
"data, ",
"internalOnly",
") VALUES (",
"?1, ",
"?2 ",
")"
].join('');
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, data);
statement.bindInt64Parameter(1, internalOnly);
statement.execute();
statement.reset();
this.app.log("storage::addBlacklistData result = " + this.conn.lastInsertRowID + ")");
return this.conn.lastInsertRowID;
},
deleteBlacklistData: function(data){
var sql = "DELETE FROM blacklist WHERE data = ?1";
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, data);
statement.execute();
statement.reset();
this.app.log("deleteBlacklistData: " + data);
},
// XXX: THIS DELETS ALL BLACKLIST URLS. ONLY USED WHEN USER SPECIFIES INTENT
deleteAllBlacklist: function(){
this.app.log("storage::deleteAllBlacklist");
var sql = "DELETE FROM blacklist WHERE internalOnly = 0";
this.conn.executeSimpleSQL(sql);
},
addThumb: function(url, thumb){
this.app.log("storage::addThumb (" + url + ")");
var now = Date.now();
var sql = ["INSERT INTO thumb (",
"url,",
"createtime,",
"data",
") VALUES (",
"?1, ",
"?2, ",
"?3 ",
")"
].join('');
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, url);
statement.bindInt64Parameter(1, now);
statement.bindUTF8StringParameter(2, thumb);
statement.execute();
statement.reset();
return this.conn.lastInsertRowID;
},
getThumb: function(id){
var res = "";
var is_id = typeof id == "number";
var sql = ["SELECT ",
"data",
" FROM thumb WHERE",
(is_id? " id = ?1" : " url = ?1")
].join("");
var statement = this.conn.createStatement(sql);
if (is_id) {
statement.bindInt64Parameter(0, id);
}
else {
statement.bindUTF8StringParameter(0, id);
}
if (statement.executeStep()) {
res = statement.getString(0);
}
statement.reset();
return res;
},
querySummary: function(starttime, endtime){
var res = {};
this.app.log("storage::querySummary");
// get sums by type
var sql = ["SELECT ",
"sum(endtime - starttime), ",
"count(*), ",
"type FROM tracker WHERE ",
this._buildWhereClause(starttime, endtime),
" AND (endtime > 0)",
" GROUP BY type"].join("");
var statement = this.conn.createStatement(sql);
res.types = [];
while (statement.executeStep()) {
res.types.push(
{
type: statement.getString(2),
timespent: statement.getInt64(0),
count: statement.getInt64(1)
}
);
}
statement.reset();
var types = res.types;
var len = types.length;
res.urls = {};
for(var x = 0; x < len; x++){
var type = types[x].type;
res.urls[type] = [];
var sql = ["SELECT ",
"sum(endtime - starttime), ",
"type, ",
"title, ",
"ftsrowid, ",
"id, ",
"url FROM tracker WHERE ",
this._buildWhereClause(starttime, endtime,[type]),
" AND (endtime > 0)",
" GROUP BY url ORDER BY sum(endtime - starttime) DESC LIMIT 5"].join("");
var statement = this.conn.createStatement(sql);
var a = res.urls[type];
while (statement.executeStep()) {
a.push(
{
url: statement.getString(5),
type: statement.getString(1),
title: statement.getString(2),
ftsrowid: statement.getInt64(3),
id: statement.getInt64(4),
timespent: statement.getInt64(0),
}
);
}
statement.reset();
}
return res;
},
queryTrackerByTrackerID: function(id){
var res = [];
this.app.log("storage::queryTrackerByTrackerID");
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE id = ?1"
].join("");
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
if (statement.executeStep()) {
res.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
endtime: statement.getInt64(4),
starttime: statement.getInt64(3),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
} else {
return [];
}
statement.reset();
// also grab the web version
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ftsrowid = ?1",
" AND type = 'web'"
].join("");
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, res[0].ftsrowid);
while (statement.executeStep()) {
res.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
endtime: statement.getInt64(4),
starttime: statement.getInt64(3),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
return res;
},
queryTrackerByFTSRowId: function(id){
var res = [];
this.app.log("storage::queryTrackerByFTSRowId");
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ftsrowid = ?1"
].join("");
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
while (statement.executeStep()) {
res.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
endtime: statement.getInt64(4),
starttime: statement.getInt64(3),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
statement.reset();
return res;
},
_queryTrackerBuildQuery: function(starttime, endtime, types, query, dedupe, getcount){
var selectfields;
if(getcount){
selectfields = "count(*)";
} else {
selectfields = [
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview"].join('');
}
if(query){
return ["SELECT ",
selectfields,
" FROM tracker WHERE ftsrowid IN (",
"SELECT id FROM historyfts WHERE (starttime>=",
starttime, " AND starttime <=", endtime,
") AND historyfts MATCH :query) AND ",
this._buildWhereClause(starttime, endtime, types, true, dedupe)].join("");
}
return ["SELECT ",
selectfields,
" FROM tracker WHERE ",
this._buildWhereClause(starttime, endtime, types, false, dedupe)].join("");
},
FTSIDToURL: function(id){
var sql = "SELECT url FROM tracker WHERE ftsrowid = ?1 LIMIT 1";
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
if (statement.executeStep()) {
return statement.getString(0);
}
return "";
},
IDToURL: function(id){
var sql = "SELECT url FROM tracker WHERE id = ?1";
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
if (statement.executeStep()) {
return statement.getString(0);
}
return "";
},
IDToTitle: function(id){
var sql = "SELECT title FROM tracker WHERE id = ?1";
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
if (statement.executeStep()) {
return statement.getString(0);
}
return " ";
},
queryTrackerByID: function(id, order, offset, max, getcount, desc, types, starttime, endtime){
this.app.log("storage::queryTrackerByID");
var whereclause = "";
if(starttime > 0){
whereclause += " AND (starttime >= " + parseInt(starttime) + ")";
}
if(endtime > 0){
whereclause += " AND (starttime <= " + parseInt(endtime) + ")";
}
var r = [];
r.push(" AND (");
var len = types.length;
for(var x = 0; x < len; ){
r.push("type = '", types[x], "'");
x++;
if(x < len){
r.push(" OR ");
}
}
r.push(")");
var typeclause = r.join("");
var res = { totalcount: 0, data: [] };
var url = this.IDToURL(id);
if(!url.length){
return res;
}
// first get the count
if(getcount){
var sql = ["SELECT count(*) FROM tracker WHERE ",
"url = ?1", whereclause, typeclause].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, url);
if (statement.executeStep()) {
res.totalcount = statement.getInt64(0);
}
statement.reset();
this.app.debug("Total: " + res.totalcount);
}
// clean order
switch(order){
case 'timespent':
order = '(endtime - starttime)';
break;
case 'title':
case 'url':
case 'starttime':
case 'type':
break;
default:
order = 'starttime';
break;
}
// now get the data
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ",
"url = ?1",whereclause, typeclause,
" ORDER BY ", order, (desc ? " DESC" : ""),
" LIMIT ", max,
" OFFSET ", offset].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, url);
while (statement.executeStep()) {
res.data.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
this.app.debug("Num Results: " + res.data.length);
statement.reset();
return res;
},
queryTrackerByMoreItems: function(type, starttime, endtime, order, offset, max, getcount, desc){
var res = { totalcount: 0, data: [] };
this.app.log("storage::queryTrackerByMoreItems");
// first get the count
if(getcount){
var sql = ["SELECT id FROM tracker WHERE ",
this._buildWhereClause(starttime, endtime, [type], false, false),
" GROUP BY url, preview"
].join("");
var sql2 = ["SELECT COUNT(*) FROM (",
sql,
")"
].join("");
var statement = this.conn.createStatement(sql2);
if (statement.executeStep()) {
res.totalcount = statement.getInt64(0);
}
statement.reset();
this.app.debug("Total: " + res.totalcount);
}
// clean order
switch(order){
case 'timespent':
order = '(endtime - starttime)';
break;
case 'title':
case 'url':
case 'starttime':
case 'type':
break;
default:
order = 'starttime';
break;
}
// now get the data
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ",
this._buildWhereClause(starttime, endtime, [type], false, false),
" GROUP BY url, preview",
" ORDER BY ", order, (desc ? " DESC" : ""),
" LIMIT ", max,
" OFFSET ", offset].join("");
var statement = this.conn.createStatement(sql);
while (statement.executeStep()) {
res.data.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
this.app.debug("Num Results: " + res.data.length);
statement.reset();
return res;
},
_cleanQuery: function(query){
// sqlite crashes when there is a + or - in a match
return query.replace(/[+-]/g,' ');
},
queryTrackerBySERP: function(query){
var res = { totalcount: 0, data: [] };
this.app.log("storage::queryTrackerBySERP");
query = this._cleanQuery(query);
// first get the count
var sql = "SELECT count(DISTINCT url) FROM historyfts WHERE historyfts MATCH ?1 AND url NOT LIKE '%google.%'";
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, query);
if (statement.executeStep()) {
res.totalcount = statement.getInt64(0);
}
statement.reset();
this.app.debug("Total: " + res.totalcount);
// now get the data
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ",
"ftsrowid IN (",
"SELECT id FROM historyfts WHERE historyfts MATCH ?1 AND url NOT LIKE '%google.%')",
"GROUP BY url",
" ORDER BY starttime DESC",
" LIMIT 3",
" OFFSET 0"].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, query);
while (statement.executeStep()) {
res.data.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
this.app.debug("Num Results: " + res.data.length);
statement.reset();
return res;
},
queryTrackerBySearch: function(query, order, offset, max, getcount, desc, types, starttime, endtime){
var res = { totalcount: 0, data: [] };
this.app.log("storage::queryTrackerBySearch");
query = this._cleanQuery(query);
var whereclause = "";
if(starttime > 0){
whereclause += " AND (starttime >= " + starttime + ")";
}
if(endtime > 0){
whereclause += " AND (starttime <= " + endtime + ")";
}
var r = [];
r.push(" AND (");
var len = types.length;
for(var x = 0; x < len; ){
r.push("type = '", types[x], "'");
x++;
if(x < len){
r.push(" OR ");
}
}
r.push(")");
var typeclause = r.join("");
// first get the count
if(getcount){
var sql = ["SELECT count(DISTINCT title)",
" FROM tracker WHERE ",
"ftsrowid IN (",
"SELECT id FROM historyfts WHERE historyfts MATCH ?1)",
whereclause, typeclause].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, query);
if (statement.executeStep()) {
res.totalcount = statement.getInt64(0);
}
statement.reset();
this.app.debug("Total: " + res.totalcount);
}
// clean order
switch(order){
case 'timespent':
order = '(endtime - starttime)';
break;
case 'title':
case 'url':
case 'starttime':
case 'type':
break;
default:
order = 'starttime';
break;
}
// now get the data
var sql = ["SELECT ",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"id,",
"preview FROM tracker WHERE ",
"ftsrowid IN (",
"SELECT id FROM historyfts WHERE historyfts MATCH ?1)",
whereclause, typeclause,
" GROUP BY title ",
" ORDER BY ", order, (desc ? " DESC" : ""),
" LIMIT ?3",
" OFFSET ?4"].join("");
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, query);
statement.bindUTF8StringParameter(1, order);
statement.bindInt64Parameter(2, max);
statement.bindInt64Parameter(3, offset);
while (statement.executeStep()) {
res.data.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
id: statement.getInt64(6),
preview: statement.getString(7)
}
);
}
this.app.debug("Num Results: " + res.data.length);
statement.reset();
return res;
},
queryTrackerByCategory: function(starttime, endtime, types, query, max, dedupe){
var res = {};
this.app.log("storage::queryTrackerByCategory: " + query);
var len = types.length;
for(var x = 0; x < len; x++){
var type = types[x];
// builds a sql statement with :query as a bind parameter
var sql = this._queryTrackerBuildQuery(starttime, endtime, [type], query, dedupe);
sql += "GROUP BY url, preview ORDER BY id DESC";
if(max){
sql += " LIMIT " + max;
}
var statement = this.conn.createStatement(sql);
if (query) {
var queryidx = statement.getParameterIndex(":query");
statement.bindUTF8StringParameter(queryidx, query);
}
while (statement.executeStep()) {
var url = statement.getString(0);
if(!res.hasOwnProperty(type)){
res[type] = [];
}
res[type].push(
{
url: url,
title: statement.getString(1),
type: type,
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
preview: statement.getString(7),
id: statement.getInt64(6)
}
);
}
statement.reset();
}
return res;
},
queryTrackerByThumbnail: function(starttime, endtime, types, query, offset, max){
var res = [];
var total = 0;
this.app.log("storage::queryTracker: " + query);
// first get count
var sql = this._queryTrackerBuildQuery(starttime, endtime, types, query, false, true);
var statement = this.conn.createStatement(sql);
if (query) {
var queryidx = statement.getParameterIndex(":query");
statement.bindUTF8StringParameter(queryidx, query);
}
if(statement.executeStep()){
total = statement.getInt64(0);
}
statement.reset();
// next get our data
var sql = this._queryTrackerBuildQuery(starttime, endtime, types, query) +
"ORDER BY starttime DESC LIMIT " + max + " OFFSET " + offset;
var statement = this.conn.createStatement(sql);
if (query) {
var queryidx = statement.getParameterIndex(":query");
statement.bindUTF8StringParameter(queryidx, query);
}
while (statement.executeStep()) {
res.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
preview: statement.getString(7),
id: statement.getInt64(6)
}
);
}
this.app.debug("Num Results: " + res.length);
statement.reset();
return { total: total, data: res };
},
queryTracker: function(starttime, endtime, types, query){
var res = [];
this.app.log("storage::queryTracker: " + query);
// builds a sql statement with :query as a bind parameter
var sql = this._queryTrackerBuildQuery(starttime, endtime, types, query);
var statement = this.conn.createStatement(sql);
if (query) {
var queryidx = statement.getParameterIndex(":query");
statement.bindUTF8StringParameter(queryidx, query);
}
while (statement.executeStep()) {
res.push(
{
url: statement.getString(0),
title: statement.getString(1),
type: statement.getString(2),
starttime: statement.getInt64(3),
endtime: statement.getInt64(4),
ftsrowid: statement.getInt64(5),
preview: statement.getString(7),
id: statement.getInt64(6)
}
);
}
this.app.debug("Num Results: " + res.length);
statement.reset();
return res;
},
resetDB: function(){
this.app.debug("storage::resetDB");
// for now, delete any old dbs
var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("boomtango.sqlite");
try {
file.remove(false);
} catch(e){}
},
upgradeDB: function(){
this.app.debug("storage::upgradeDB to " + this.DBVERSION);
// for now, delete any old dbs
var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("boomtango.sqlite");
try {
file.remove(false);
} catch(e){}
this.app.dbversion = this.DBVERSION;
},
_fileCopy: function(fromFile, toFile) {
try {
// READ file (binary)
var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
istream.init(fromFile, -1, -1, false);
var bstream = Components.classes["@mozilla.org/binaryinputstream;1"].
createInstance(Components.interfaces.nsIBinaryInputStream);
bstream.setInputStream(istream);
var bytes = bstream.readBytes(bstream.available());
this.app.log("READ FILE LENGTH: " + bytes.length);
// WRITE file (binary)
var ostream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
ostream.init(toFile, 0x04 | 0x08 | 0x20, 0600, 0); // write, create, truncate
ostream.write(bytes, bytes.length);
if (ostream instanceof Components.interfaces.nsISafeOutputStream) {
ostream.finish();
} else {
ostream.close();
}
}
catch (err) {
this.app.log("ERROR: " + err);
return false;
}
return true;
},
backupToFile: function(filename){
var backupfile = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
backupfile.initWithPath(filename);
var dbfile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
dbfile.append("boomtango");
dbfile.append("data");
dbfile.append("boomtango.sqlite");
return this._fileCopy(dbfile, backupfile);
},
validBackup: function(file){
try {
// check if we can open db
var storageService = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var backupconn = storageService.openUnsharedDatabase(file);
var sql = "select name from SQLite_Master";
var statement = backupconn.createStatement(sql);
var res = [];
while (statement.executeStep()) {
// create a hash
res[statement.getString(0)] = true;
this.app.log("VALIDATE:" + statement.getString(0));
}
// verify existance of required tables
var required_tables = ["tracker",
"thumb",
"blacklist"];
this.app.debug("Num Results: " + res.length);
for (x in required_tables) {
if (!res[required_tables[x]]) {
this.app.log('cant find ' + required_tables[x]);
return false;
}
}
statement.reset();
}
catch (ex) {
return false;
}
return true;
},
restoreFromFile: function(filename){
var backupfile = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
backupfile.initWithPath(filename);
var dbfile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
dbfile.append("boomtango");
dbfile.append("data");
dbfile.append("boomtango.sqlite");
if (!this.validBackup(backupfile)) {
return false;
}
this._fileCopy(backupfile, dbfile);
// re-initialize
var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("boomtango");
file.append("data");
file.append("boomtango.sqlite");
this.app.log("dbversion=" + this.DBVERSION);
this.app.log("current version=" + this.app.dbversion);
if(this.app.dbversion < this.DBVERSION){
this.upgradeDB();
}
var storageService = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
this.conn = storageService.openUnsharedDatabase(file);
this.app.debug("storage::re-init");
this.app.reloadTabsWithAttribute("boomtangoHistory");
return true;
},
init: function(app){
this.app = app;
var file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("boomtango");
file.append("data");
file.append("boomtango.sqlite");
this.app.log("dbversion=" + this.DBVERSION);
this.app.log("current version=" + this.app.dbversion);
if(this.app.killBTData){
this.app.killBTData = false;
this.resetDB();
} else if(this.app.dbversion < this.DBVERSION){
this.upgradeDB();
}
var storageService = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var newdb = !file.exists();
this.conn = storageService.openUnsharedDatabase(file);
this.app.debug("storage::init");
if(newdb){
this.initTables();
this.loadFromHistory();
}
this.init = function(){};
},
loadFromHistory: function(){
this.app.debug("storage::loadFromHistory");
this.app.newUser = true;
},
cleanupDB: function(){
var lastcleanup = this.app.lastcleanup;
var lastshutdown = this.app.lastshutdown;
var self = this;
// write our current time each minute in case of crash
var callback = {
notify: function(){
var d = new Date();
self.app.lastshutdown = d.getTime();
}
};
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(callback, 60*1000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
callback.notify();
var query = ["UPDATE tracker SET endtime=",
lastshutdown, " WHERE ",
"starttime > ", lastcleanup, " AND endtime < 0"
].join('');
this.conn.executeSimpleSQL(query);
var now = new Date();
this.app.lastcleanup = now.getTime();
},
initTables: function() {
this.app.debug("storage::inittables");
this.conn.executeSimpleSQL("create virtual table historyfts using fts3(title TEXT,content TEXT, url TEXT, starttime INTEGER, endtime INTEGER, id INTEGER);");
// Setup thumb table
this.conn.executeSimpleSQL(["CREATE TABLE IF NOT EXISTS thumb (",
"id INTEGER PRIMARY KEY,",
"url TEXT,",
"createtime INTEGER,",
"data TEXT)"
].join(''));
this.conn.executeSimpleSQL(["CREATE INDEX IF NOT EXISTS thumb_url_index ",
"ON thumb (url)"
].join(''));
// Setup blacklist table
this.conn.executeSimpleSQL(["CREATE TABLE IF NOT EXISTS blacklist (",
"id INTEGER PRIMARY KEY,",
"internalOnly INTEGER,",
"data TEXT)"
].join(''));
this.addBlacklistData("chrome://*", 1);
this.addBlacklistData("about:*", 1);
// Setup tracker table
this.conn.executeSimpleSQL(["CREATE TABLE IF NOT EXISTS tracker (",
"id INTEGER PRIMARY KEY,",
"url TEXT,",
"title TEXT,",
"type TEXT,",
"ftsrowid INTEGER,",
"starttime INTEGER,",
"endtime INTEGER,",
"preview TEXT)"
].join(''));
this.conn.executeSimpleSQL(["CREATE INDEX IF NOT EXISTS ftsrowid_index ",
"ON tracker (ftsrowid)"
].join(''));
this.conn.executeSimpleSQL(["CREATE INDEX IF NOT EXISTS starttime_index ",
"ON tracker (starttime)"
].join(''));
},
addFTS: function(title, content, starttime, endtime, url){
this.app.log("storage::addFTS: " + title);
this.app.log("(" + url + ")");
var sql = ["INSERT INTO historyfts (",
"title,",
"content, url, starttime, endtime, id) VALUES (",
"?1, ",
"?2, ?3, ?4, ?5, ?6)"
].join('');
var statement = this.conn.createStatement(sql);
var result = this.app.getNextID();
statement.bindUTF8StringParameter(0, title);
statement.bindUTF8StringParameter(1, content);
statement.bindUTF8StringParameter(2, url);
statement.bindInt64Parameter(3, starttime);
statement.bindInt64Parameter(4, endtime);
statement.bindInt64Parameter(5, result);
statement.execute();
statement.reset();
return result;
},
/* Tracker Commands */
addTrackers: function(url, title, ftsrowid, starttime, endtime, trackers){
this.app.log("storage::addTrackers: " + title + " (" + trackers.length + ")");
if(trackers){
var len = trackers.length;
while(len--){
var trackertitle = trackers[len].title || title;
this._addTracker(url, trackertitle, ftsrowid, starttime, endtime, trackers[len]);
}
}
},
_addTracker: function(url, title, ftsrowid, starttime, endtime, tracker) {
var sql = ["INSERT INTO tracker (",
"url,",
"title,",
"type,",
"starttime,",
"endtime,",
"ftsrowid,",
"preview) VALUES (",
"?1, ",
"?2, ",
"?3, ",
"?4, ",
"?5, ",
"?6, ",
"?7)"
].join('');
var statement = this.conn.createStatement(sql);
statement.bindUTF8StringParameter(0, url);
statement.bindUTF8StringParameter(1, title);
statement.bindUTF8StringParameter(2, tracker.type);
statement.bindInt64Parameter(3, starttime);
statement.bindInt64Parameter(4, endtime);
statement.bindUTF8StringParameter(5, ftsrowid);
statement.bindUTF8StringParameter(6, tracker.preview);
statement.execute();
statement.reset();
return this.conn.lastInsertRowID;
},
// XXX: THIS DELETS ALL TRACKERS. ONLY USED WHEN USER SPECIFIES INTENT
deleteAllTrackers: function(){
this.app.log("storage::deleteAllTrackers");
var sql = "DELETE FROM tracker";
this.conn.executeSimpleSQL(sql);
},
deleteTrackersForFTSRowId: function(id){
this.app.log("storage::deleteTrackersForFTSRowId: " + id);
var sql = "DELETE FROM tracker WHERE ftsrowid = ?1";
var statement = this.conn.createStatement(sql);
statement.bindInt64Parameter(0, id);
statement.executeStep();
statement.reset();
},
deleteTrackersForURL: function(url){
this.app.log("storage::deleteTrackersForURL: " + url);
var sql = ["DELETE FROM tracker WHERE url = '",
url, "'"].join("");
this.conn.executeSimpleSQL(sql);
},
updateTrackerEnd: function(url, end, ftsrowid){
var sql = ["UPDATE tracker SET endtime = ", end, " WHERE url = '",
url, "'", " AND endtime < 0"].join("");
this.conn.executeSimpleSQL(sql);
}
};